import yaml
import time
import argparse
import sys
import os
import librosa
from pathlib import Path

# 将 src 目录添加到 Python 路径中
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

# 导入路径管理器和模块
from src.utils import CONFIG_PATH, DATABASE_PATH
from src.database import Database
from src.fingerprinting.processor import Processor
from src.fingerprinting.hashing import Hasher
from src.matching.scorer import Scorer

def print_diagnostics(diagnostics: dict, db: Database):
    """
    以可读格式打印诊断信息，主要是时间偏移直方图。
    Prints diagnostic information, primarily the time offset histogram, in a readable format.
    """
    print("\n" + "="*20 + " DIAGNOSTICS " + "="*20)
    histogram = diagnostics.get('histogram', {})
    if not histogram:
        print("Histogram is empty.")
        return

    # 获取所有涉及的歌曲信息
    all_song_ids = list(histogram.keys())
    song_info_map = {song_id: db.get_song_by_id(song_id) for song_id in all_song_ids}

    print("\n[Time Offset Histogram]")
    print("-" * 53)
    print(f"{'Song ID':<8} | {'Song Name':<25} | {'Offset (s)':<10} | Votes")
    print("-" * 53)

    # 排序并打印每个歌曲的直方图数据
    for song_id, buckets in sorted(histogram.items(), key=lambda item: sum(item[1].values()), reverse=True):
        song_name = song_info_map.get(song_id, {}).get('name', 'Unknown')
        # 对每个歌曲的偏移量按票数排序
        for offset, votes in sorted(buckets.items(), key=lambda item: item[1], reverse=True):
            print(f"{song_id:<8} | {song_name[:25]:<25} | {offset:<10} | {votes}")

    print("="*53 + "\n")


def recognize_audio(sample_path: Path, config_path: Path, db_path: Path, verbose: bool = False):
    """
    使用确定的绝对路径识别音频样本。
    Recognizes an audio sample using resolved absolute paths.
    """
    # 1. 加载配置
    with open(config_path, 'r', encoding='utf-8') as f:
        config = yaml.safe_load(f)

    # 2. 初始化模块
    db = Database(str(db_path))
    processor = Processor(config)
    hasher = Hasher(config['hashing'])
    scorer = Scorer(config['scoring'])

    start_time = time.time()

    # 3. 为样本生成指纹
    print(f"Processing sample: {sample_path.name}...")
    sample_peaks = processor.audio_to_peaks(str(sample_path))
    if not sample_peaks.any():
        print("Could not find any peaks in the sample. Cannot recognize.")
        return

    sample_fingerprints = hasher.peaks_to_fingerprints(sample_peaks)
    if not sample_fingerprints:
        print("Could not generate fingerprints for the sample. Cannot recognize.")
        return

    processing_time = time.time() - start_time
    print(f"  -> Generated {len(sample_fingerprints)} fingerprints in {processing_time:.2f}s.")

    # 4. 查询数据库
    query_hashes = [fp[0] for fp in sample_fingerprints]
    search_start_time = time.time()
    with db:
        db_matches = db.find_matches(query_hashes)
    search_time = time.time() - search_start_time

    num_matches = sum(len(v) for v in db_matches.values())
    print(f"  -> Found {num_matches} total matches in database in {search_time:.2f}s.")

    # 5. 评分
    scoring_start_time = time.time()
    result, diagnostics = None, None

    # 根据 verbose 标志调用评分器
    match_output = scorer.find_best_match(sample_fingerprints, db_matches, return_diag_info=verbose)
    if verbose:
        result, diagnostics = match_output
    else:
        result = match_output

    scoring_time = time.time() - scoring_start_time
    print(f"  -> Scored matches in {scoring_time:.2f}s.")

    total_time = time.time() - start_time

    # 6. 打印结果
    print("-" * 40)
    if result:
        with db:
            song_info = db.get_song_by_id(result['song_id'])

        print(f"✅ Match Found! (Total time: {total_time:.2f}s)")
        print(f"   Song: {song_info.get('name', 'N/A')}")
        print(f"   Artist: {song_info.get('artist', 'N/A')}")
        print(f"   Confidence: {result['confidence']:.2f}%")
        print(f"   Time Offset in song: ~{result['offset']}s")
        print("\n   Matching Metrics:")
        for key, value in result['metrics'].items():
            print(f"     - {key}: {value}")
    else:
        print(f"❌ No confident match found. (Total time: {total_time:.2f}s)")
    print("-" * 40)

    # 7. 如果需要，打印诊断信息
    if verbose and diagnostics:
        with db:
            print_diagnostics(diagnostics, db)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Recognize an audio sample.")
    parser.add_argument('sample_path', type=Path, help="Path to the audio sample file to recognize.")
    parser.add_argument(
        '--verbose',
        action='store_true',
        help="Output detailed diagnostic information, including the offset histogram."
    )
    args = parser.parse_args()

    if not args.sample_path.exists():
        print(f"Error: Sample file not found at '{args.sample_path}'")
    else:
        recognize_audio(args.sample_path, CONFIG_PATH, DATABASE_PATH, verbose=args.verbose)
